import {
  any
} from "../../../core/logic";
import {
  Compute
} from "./Compute";
import {
  gtao,
  gtao_multisampled
} from "./shaders/gtao";
import {
  Pass
} from "../Pass";
import {
  Engine
} from "../../../Engine";
import {
  guid
} from "../../../core/utils";
/**
 * @class
 * @memberof w.compute
 */
class MergeSample extends Compute {
  constructor(opts = {}) {
    super(opts);
  }
  generateComputeShaderCode(textureArray) {
    let bindGroup = ``
    let SumVariables = ``
    let SampleLoop = ``
    let AverageAndStore = ``
    const getDefine = (textureArray) => {
      for (let index = 0; index < textureArray.length; index++) {
        const tex = textureArray[index].multi;
        if (tex.format === 'depth24plus-stencil8') {
          bindGroup += `
          @group(0) @binding(${index * 2}) var ${tex.label}_multi: texture_depth_multisampled_2d;
          @group(0) @binding(${index * 2 + 1}) var ${tex.label}_one: texture_storage_2d<rgba8unorm, write>;`
          SumVariables += `var ${tex.label}Sum: f32 = 0.0;`
          AverageAndStore += `var average${tex.label} = ${tex.label}Sum / f32(4);textureStore(${tex.label}_one, vec2<i32>(globalId.xy),vec4<f32>(average${tex.label},0,0,0) );`
        }
        if (tex.format === 'rgba16float') {
          bindGroup += `
          @group(0) @binding(${index * 2}) var ${tex.label}_multi: texture_multisampled_2d<f32>;
          @group(0) @binding(${index * 2 + 1}) var ${tex.label}_one: texture_storage_2d<rgba16float, write>;`
          SumVariables += `var ${tex.label}Sum: vec4<f32> = vec4<f32>(0.0, 0.0, 0.0, 0.0);`
          AverageAndStore += `var average${tex.label} = ${tex.label}Sum / f32(4);textureStore(${tex.label}_one, vec2<i32>(globalId.xy), average${tex.label});`
        }
        if (tex.format === 'rgba32float') {
          bindGroup += `
          @group(0) @binding(${index * 2}) var ${tex.label}_multi: texture_multisampled_2d<f32>;
          @group(0) @binding(${index * 2 + 1}) var ${tex.label}_one: texture_storage_2d<rgba32float, write>;`
          SumVariables += `var ${tex.label}Sum: vec4<f32> = vec4<f32>(0.0, 0.0, 0.0, 0.0);`
          AverageAndStore += `var average${tex.label} = ${tex.label}Sum / f32(4);textureStore(${tex.label}_one, vec2<i32>(globalId.xy), average${tex.label});`
        }
        if (tex.format === 'rgba8unorm') {
          bindGroup += `
          @group(0) @binding(${index * 2}) var ${tex.label}_multi: texture_multisampled_2d<f32>;
          @group(0) @binding(${index * 2 + 1}) var ${tex.label}_one: texture_storage_2d<rgba8unorm, write>;`
          SumVariables += `var ${tex.label}Sum: vec4<f32> = vec4<f32>(0.0, 0.0, 0.0, 0.0);`
          AverageAndStore += `var average${tex.label} = ${tex.label}Sum / f32(4);textureStore(${tex.label}_one, vec2<i32>(globalId.xy), average${tex.label});`
        }
        SampleLoop += `${tex.label}Sum+=textureLoad(${tex.label}_multi, vec2<i32>(globalId.xy),i);`

      }

    }
    getDefine(textureArray)
    let wgslCode = `
    ${bindGroup}
    @compute @workgroup_size(16, 16)
    fn main(@builtin(global_invocation_id) globalId : vec3<u32>) {
        ${SumVariables}
        for (var i: u32 = 0u; i < 4; i = i + 1u) {
          let sampleIndex = i;
          ${SampleLoop}
        }
       ${AverageAndStore}
      }
     `;
    return wgslCode;
  }
  initPipeLine(textureArray) {
    if (!this.computePipeline || this.computePipeline?.id != textureArray.id) {
      const wgslCode = this.generateComputeShaderCode(textureArray)
      // 创建着色器模块
      const shaderModule = Engine.instance.device.createShaderModule({
        code: wgslCode
      });
      // 创建计算管线
      this.computePipeline = Engine.instance.device.createComputePipeline({
        layout: 'auto',
        compute: {
          module: shaderModule,
          entryPoint: 'main',
        },
      });
      this.computePipeline.id = textureArray.id
    }
  }
  initBindGroup(textureArray) {
    // 创建绑定组
    if (!this.bindGroup || this.bindGroup?.id != textureArray.id) {
      let entries = []
      for (let index = 0; index < textureArray.length; index++) {
        const tex = textureArray[index];
        entries.push({ binding: 2 * index, resource: tex.multi.view })
        entries.push({ binding: 2 * index + 1, resource: tex.one.view })
      }
      this.bindGroup = Engine.instance.device.createBindGroup({
        label: "merge group",
        layout: this.computePipeline.getBindGroupLayout(0),
        entries: entries,
      });
      this.bindGroup.id = textureArray.id
    }
  }
  getOneTextures(textureArray, commandEncoder) {
    this.initPipeLine(textureArray)
    this.initBindGroup(textureArray)
    const workerSizeX = Math.ceil(Engine.instance.size[0] / 16);
    const workerSizeY = Math.ceil(Engine.instance.size[1] / 16);
    const workerSizeZ = 1;
    const computePass = commandEncoder.beginComputePass();
    computePass.setPipeline(this.computePipeline);
    computePass.setBindGroup(0, this.bindGroup);
    computePass.dispatchWorkgroups(workerSizeX, workerSizeY, workerSizeZ);
    computePass.end();
  }
  onCompute(commandEncoder) {
    // const commandEncoder = Engine.instance.device.createCommandEncoder()
    this.initPipeLine()
    this.initBindGroup()
    const workerSizeX = Math.ceil(Engine.instance.size[0] / 16);
    const workerSizeY = Math.ceil(Engine.instance.size[1] / 16);
    const workerSizeZ = 1;
    const computePass = commandEncoder.beginComputePass();
    computePass.setPipeline(this.computePipeline);
    computePass.setBindGroup(0, this.bindGroup);
    computePass.dispatchWorkgroups(workerSizeX, workerSizeY, workerSizeZ);
    computePass.end();
    // const commands = commandEncoder.finish({ label: "GTAO" });
    // Engine.instance.queue.submit([commands]);
  }
}
export {
  MergeSample
};
